package com.bwstudio.common.unires.handler;

import javax.servlet.http.HttpServletRequest;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.bwstudio.common.response.BasicResponseCodeEnum;
import com.bwstudio.common.response.IResponseCode;
import com.bwstudio.common.response.Result;
import com.bwstudio.common.unires.exception.BusinessException;

import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@ConditionalOnProperty(prefix = "unified-response", value = "enabled", havingValue = "true")
@RestControllerAdvice
public class BaseGlobalExceptionHandler {

	/* 处理400类异常 */
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	@ExceptionHandler(ConstraintViolationException.class)
//	public Result handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
//		return super.handleConstraintViolationException(e, request);
//	}
//
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	@ExceptionHandler(HttpMessageNotReadableException.class)
//	public Result handleConstraintViolationException(HttpMessageNotReadableException e, HttpServletRequest request) {
//		return super.handleConstraintViolationException(e, request);
//	}
//
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	@ExceptionHandler(BindException.class)
//	public Result handleBindException(BindException e, HttpServletRequest request) {
//		return super.handleBindException(e, request);
//	}
//
//	@ResponseStatus(HttpStatus.BAD_REQUEST)
//	@ExceptionHandler(MethodArgumentNotValidException.class)
//	public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
//		return super.handleMethodArgumentNotValidException(e, request);
//	}
	
	 /**
	  * 处理未捕获的Exception
	  * @param e 异常
	  * @return 统一响应体
	  */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(Exception.class)
	public Result handleException(Exception e, HttpServletRequest request) {
		log.error("handleException start, uri:{}, caused by: ", request.getRequestURI(), e);
		return Result.failure(BasicResponseCodeEnum.SERVER_INNER_ERROR);
	}

	/***
	 * @Description: 请求参数校验失败的统一异常处理
	 * @Author: 卜伟
	 * @Date: 2020/5/26 10:18

	 * @param e
	 * @return: com.bwstudio.common.response.Result
	**/
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(value = { MethodArgumentNotValidException.class, BindException.class})
	public Result handleVaildException(Exception e) {
		BindingResult bindingResult = null;
		if (e instanceof MethodArgumentNotValidException) {
			bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
		} else if (e instanceof BindException) {
			bindingResult = ((BindException) e).getBindingResult();
		}
		Map<String, String> errorMap = new HashMap<>(16);
		bindingResult.getFieldErrors().forEach((fieldError) ->
				errorMap.put(fieldError.getField(), fieldError.getDefaultMessage())
		);
		return Result.failure(BasicResponseCodeEnum.PARAMETER_ILLEGAL, errorMap);
	}

	 /**
	  * 处理未捕获的RuntimeException
	  * @param e 运行时异常
	  * @return 统一响应体
	  */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(RuntimeException.class)
	public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) {
		//TODO 可通过邮件、微信公众号等方式发送信息至开发人员、记录存档等操作
		log.error("handleRuntimeException start, uri: {}, caused by: ", 
				request.getRequestURI(), e);
		return Result.failure(BasicResponseCodeEnum.SERVER_INNER_ERROR);
	}
	 
	 /**
	  * 处理业务异常BaseException
	  * @param e 业务异常
	  * @return 统一响应体
	  */
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ExceptionHandler(BusinessException.class)
	public Result handleBusinessException(BusinessException e, HttpServletRequest request) {
		log.error("handleBusinessException start, uri: {}, exception: {}, caused by: {}", 
				request.getRequestURI(), e.getClass(), e.getMessage());
		return Result.failure(new IResponseCode() {
			@Override
			public String getMessage() {
				return e.getMessage();
			}
			@Override
			public String getCode() {
				return e.getCode();
			}
		});
	}
}
